package com.tianji.learning.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.api.client.course.CourseClient;
import com.tianji.api.dto.course.CourseFullInfoDTO;
import com.tianji.api.dto.leanring.LearningLessonDTO;
import com.tianji.api.dto.leanring.LearningRecordDTO;
import com.tianji.common.exceptions.DbException;
import com.tianji.common.utils.BeanUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.domain.LearningLesson;
import com.tianji.learning.domain.LearningRecord;
import com.tianji.learning.domain.dto.LearningRecordFormDTO;
import com.tianji.learning.enums.LessonStatus;
import com.tianji.learning.enums.SectionType;
import com.tianji.learning.service.LearningLessonService;
import com.tianji.learning.service.LearningRecordService;
import com.tianji.learning.mapper.LearningRecordMapper;
import com.tianji.learning.utils.LearningRecordDelayTaskHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;
import java.util.zip.DeflaterOutputStream;

/**
 * @author 阿娇的秘密星球
 * @description 针对表【learning_record(学习记录表)】的数据库操作Service实现
 * @createDate 2024-12-19 15:12:30
 */
@Service
public class LearningRecordServiceImpl extends ServiceImpl<LearningRecordMapper, LearningRecord>
        implements LearningRecordService {

    @Autowired
    private LearningLessonService learningLessonService;

    @Override
    public LearningLessonDTO queryLearningRecordByCourse(Long courseId) {
        LearningLesson learningLesson = learningLessonService.lambdaQuery()
                .eq(LearningLesson::getUserId, UserContext.getUser())
                .eq(LearningLesson::getCourseId, courseId)
                .select(LearningLesson::getId, LearningLesson::getLatestSectionId)
                .one();

        LearningLessonDTO learningLessonDTO = BeanUtils.copyBean(learningLesson, LearningLessonDTO.class);
        List<LearningRecord> learningRecordList = this.lambdaQuery().eq(LearningRecord::getLessonId, learningLessonDTO.getId())
                .list();
        List<LearningRecordDTO> learningRecordDTOList = BeanUtils.copyList(learningRecordList, LearningRecordDTO.class);
        learningLessonDTO.setRecords(learningRecordDTOList);
        return learningLessonDTO;
    }

    @Override
    public void commitLearningRecords(LearningRecordFormDTO dto) {
        Long userId = UserContext.getUser();
        Boolean finish = false;
        if (dto.getSectionType().equals(SectionType.VIDEO)) {
            //视频处理
            finish = handleVideoRecord(userId, dto);
        } else {
            finish = handlerExamRecord(userId, dto);
        }
        if (!finish) {
            return;
        }
        handleLearningLessonsChanges(dto);
    }

    //更新课程
    @Autowired
    private CourseClient courseClient;

    private void handleLearningLessonsChanges(LearningRecordFormDTO dto) {
        LearningLesson learningLesson = learningLessonService.lambdaQuery().eq(LearningLesson::getId, dto.getLessonId())
                .one();
        CourseFullInfoDTO courseInfo = courseClient.getCourseInfoById(learningLesson.getCourseId(), false, false);
        // 2.判断是否有新的完成小节
        boolean allLearned = false;

        allLearned = learningLesson.getLearnedSections() + 1 >= courseInfo.getSectionNum();


        learningLessonService.lambdaUpdate()
                .eq(LearningLesson::getId, dto.getLessonId())
                .set(allLearned, LearningLesson::getStatus, LessonStatus.FINISHED.getValue())
                .set(LearningLesson::getLatestSectionId, dto.getSectionId())
                .set(LearningLesson::getLatestLearnTime, dto.getCommitTime())
                .setSql("learned_sections=learned_sections+1")
                .update();
    }

    //考试处理
    private Boolean handlerExamRecord(Long userId, LearningRecordFormDTO dto) {
        LearningRecord learningRecord = BeanUtils.copyBean(dto, LearningRecord.class);
        learningRecord.setUserId(userId);
        learningRecord.setFinishTime(dto.getCommitTime());
        this.save(learningRecord);
        return true;
    }

    //视频处理
    private boolean handleVideoRecord(Long userId, LearningRecordFormDTO recordDTO) {
        // 1.查询旧的学习记录
        LearningRecord old = readFromCache(recordDTO);
        // 2.判断是否存在
        if (old == null) {
            // 3.不存在，则新增
            // 3.1.转换PO
            LearningRecord record = BeanUtils.copyBean(recordDTO, LearningRecord.class);
            // 3.2.填充数据
            record.setUserId(userId);
            // 3.3.写入数据库
            boolean success = save(record);
            if (!success) {
                throw new DbException("新增学习记录失败！");
            }
            return false;
        }
        // 4.存在，则更新
        // 4.1.判断是否是第一次完成
        boolean finished = !old.getFinished() && recordDTO.getMoment() * 2 >= recordDTO.getDuration();
        if (finished) {
            //是第一次学完
            // 4.2.更新数据
            boolean success = lambdaUpdate()
                    .set(finished, LearningRecord::getFinished, true)
                    .set(finished, LearningRecord::getFinishTime, recordDTO.getCommitTime())
                    .eq(LearningRecord::getId, old.getId())
                    .update();
            if (!success) {
                throw new DbException("更新学习记录失败！");
            }

            handler.deleteRecordFromRedis(recordDTO.getLessonId(), recordDTO.getLessonId());
        } else {
            //不是第一次学完
            old.setMoment(recordDTO.getMoment());
            handler.add2Cache(old);
        }

        return finished;
    }

    @Autowired
    private LearningRecordDelayTaskHandler handler;


    private LearningRecord readFromCache(LearningRecordFormDTO recordDTO) {
        //从缓存查
        LearningRecord learningRecord = handler.readRecordCache(recordDTO.getLessonId(), recordDTO.getSectionId());
        //缓存中没有
        if (learningRecord == null) {
            //缓存中没有从数据库查再加到缓存中
            LearningRecord record = this.lambdaQuery()
                    .eq(LearningRecord::getLessonId, recordDTO.getLessonId())
                    .eq(LearningRecord::getSectionId, recordDTO.getSectionId())
                    .one();
            if (record == null) {
                return null;
            } else {
                handler.writeRecordToRedis(record);
                return record;
            }
        } else {
            //缓存中有直接返回
            return learningRecord;
        }

    }

    private LearningRecord queryOldRecord(Long lessonId, Long sectionId) {
        return lambdaQuery()
                .eq(LearningRecord::getLessonId, lessonId)
                .eq(LearningRecord::getSectionId, sectionId)
                .one();
    }

}




